package com.we823.project.controller.report;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.we823.project.common.file.MaterialStockUtil;
import com.we823.project.common.web.status.PermissionStatus;
import com.we823.project.controller.AbstractBaseController;
import com.we823.project.core.web.WebConstants;
import com.we823.project.model.repo.CategoryModel;
import com.we823.project.model.repo.MaterialBomModel;
import com.we823.project.model.repo.MaterialModel;
import com.we823.project.model.repo.MaterialStockModel;
import com.we823.project.model.report.BomStockReport;
import com.we823.project.repository.service.repo.CategoryService;
import com.we823.project.repository.service.repo.MaterialBomService;
import com.we823.project.repository.service.repo.MaterialService;
import com.we823.project.repository.service.repo.MaterialStockService;
import com.we823.utils.web.DateUtil;
import com.we823.utils.web.RequestUtil;

@Controller
@RequestMapping(WebConstants.REPORT_MATERIAL)
public class MaterialStockController extends
		AbstractBaseController<MaterialStockModel> {

	private Logger logger = LoggerFactory
			.getLogger(MaterialStockController.class);

	private static String baseUrl = WebConstants.REPORT_MATERIAL_TEMPLATE;
	private MaterialStockService materialStockService;
	@Autowired
	private MaterialService materialService;
	@Autowired
	private CategoryService categoryService;
	@Autowired
	private MaterialBomService materialBomService;

	@RequestMapping("getInfo")
	@ResponseBody
	public Model getInfo(HttpServletRequest request, Model model) {

		check(PermissionStatus.VIEW);
		model.addAttribute("year", DateUtil.getYear());
		model.addAttribute("currentYear", DateUtil.getYear());

		model.addAttribute("currentMonth", DateUtil.getMonth() + 1);
		model.addAttribute("currentDay", DateUtil.getDay());

		model.addAttribute("day",
				DateUtil.getMaxDay(DateUtil.getYear(), DateUtil.getMonth()));
		model.addAttribute("categories", categoryService.findAll());
		return model;
	}

	@Autowired
	public MaterialStockController(MaterialStockService materialStockService) {
		super(materialStockService);
		this.materialStockService = materialStockService;
		super.baseUrl = baseUrl;

		setResourceIdentity("report:material");
	}

	@Override
	public Page<MaterialStockModel> getData(PageRequest pageRequest,
			HttpServletRequest request, Model model, boolean pageable) {
		String code = RequestUtil.getValueByParam(request, "code");
		String action = RequestUtil.getValueByParam(request, "action", "all");

		Page<MaterialStockModel> stockPage = null;
		if (StringUtils.isEmpty(code)) {
			if (pageable) {
				stockPage = materialStockService.findAll(pageRequest);
			} else {
				stockPage = new PageImpl<MaterialStockModel>(
						materialStockService.findAll());
			}
			fillInfo(stockPage, code);
		} else {
			List<String> codeList = new ArrayList<String>();
			if ("0".equals(code)) {
				List<CategoryModel> categoryModels = categoryService.findAll();
				if (categoryModels != null) {
					for (CategoryModel categoryModel : categoryModels) {
						codeList.add(categoryModel.getCode());
					}
				}
			} else {
				codeList.add(code);
			}

			List<CategoryModel> categoryModels = categoryService
					.findByCodeIn(codeList);
			List<String> materialCodeList = new ArrayList<String>();
			Map<String, MaterialModel> materialMap = new HashMap<String, MaterialModel>();

			if (categoryModels != null && categoryModels.size() > 0) {
				List<MaterialModel> materialModels = materialService
						.findByCategoryIn(categoryModels);
				if (materialModels != null) {

					parseMaterialInfo(materialModels, materialMap,
							materialCodeList);
				}
			}
			int year = 0, month = 0, day = 0;
			switch (action) {
			case "year":
				year = RequestUtil.getValueByParam(request, "year",
						DateUtil.getYear());
				stockPage = getYearStockPage(materialCodeList, pageRequest,
						pageable, year);
				break;
			case "month":
				year = RequestUtil.getValueByParam(request, "year",
						DateUtil.getYear());
				month = RequestUtil.getValueByParam(request, "month",
						DateUtil.getMonth() + 1);
				stockPage = getMonthStockPage(materialCodeList, pageRequest,
						pageable, year, month);
				break;
			case "day":
				year = RequestUtil.getValueByParam(request, "year",
						DateUtil.getYear());
				month = RequestUtil.getValueByParam(request, "month",
						DateUtil.getMonth() + 1);
				day = RequestUtil.getValueByParam(request, "day",
						DateUtil.getDay());
				stockPage = getDayStockPage(materialCodeList, pageRequest,
						pageable, year, month, day);
				break;
			default:
				stockPage = getDefaultStockPage(pageRequest, pageable,
						stockPage, codeList);
				break;
			}
			fillInfo(stockPage, materialMap);
			// stockPage =
			// materialStockService.findByMaterialCodeStartWith(code,
			// pageRequest);
		}

		return stockPage;
	}

	@RequestMapping("exportExcel")
	@ResponseBody
	public Model exportExcel(HttpServletRequest request, Model model) {

		check(PermissionStatus.VIEW);
		Page<MaterialStockModel> materialStockModelPage = getData(null,
				request, model, false);
		if (materialStockModelPage != null) {
			List<MaterialStockModel> materialStockModels = materialStockModelPage
					.getContent();
			String action = RequestUtil.getValueByParam(request, "action",
					"year");
			MaterialStockUtil materialStockUtil = new MaterialStockUtil(action);

			String sheetname = RequestUtil.getValueByParam(request, "caption",
					"材料报表");
			String filename = DateUtil.getDateString() + ".xlsx";
			String path = WebConstants.EXCEL_PATH;
			ServletContext servletContext = request.getServletContext();
			String fullpath = servletContext.getRealPath(path);
			File filepath = new File(fullpath);
			if (!filepath.exists()) {
				filepath.mkdirs();
			}

			String fullname = fullpath + "/" + filename;
			logger.debug("create filename : {}", fullname);
			boolean result = materialStockUtil.createExcel2007(fullname,
					sheetname, materialStockModels);

			if (result) {
				model.addAttribute("result", result);
				model.addAttribute("filename", filename);
				model.addAttribute("sheetname", sheetname + ".xlsx");
			} else {
				model.addAttribute("result", false);
			}
		} else {
			model.addAttribute("result", false);
		}
		return model;
	}

	@RequestMapping("findBomStock")
	public String findBomStock(HttpServletRequest request, Model model) {

		if (permissionList != null) {
			// permissionList.assertHasViewPermission();
		}
		String code = RequestUtil.getValueByParam(request, "code");
		if (!StringUtils.isEmpty(code)) {
			MaterialModel materialModel = materialService.findByCode(code);
			if (materialModel != null) {
				List<MaterialBomModel> materialBomModels = fillBoms(materialModel
						.getCode());
				if (materialBomModels != null) {
					materialModel.setMaterialBoms(materialBomModels);
				}
				
				List<BomStockReport> bomStockReports = new ArrayList<>();
				fillBomStockReport(materialModel,bomStockReports);
				model.addAttribute("material", materialModel);
				List<String> materialCodeList = new ArrayList<>();
				if (bomStockReports!=null) {
					for (BomStockReport bomStockReport : bomStockReports) {
						materialCodeList.add(bomStockReport.getMaterialCode());
					}
				}

				Map<String, MaterialModel> map = materialService.map();
				
				Page<MaterialStockModel> stockPage = materialStockService.findByMaterialCodeIn(materialCodeList, null);
				if (stockPage!=null) {
					List<MaterialStockModel> materialStockModels = stockPage.getContent();
					if (materialStockModels!=null) {

						for (MaterialStockModel materialStockModel : materialStockModels) {
							fillBomReport(materialStockModel,bomStockReports,map);
						}
					}
				}
				
				model.addAttribute("bomStockReports",bomStockReports);
			} else {
				model.addAttribute("hasError", true);
			}
		}
		return baseUrl + "findBomStock";
	}

	private void fillBomReport(MaterialStockModel materialStockModel,
			List<BomStockReport> bomStockReports,Map<String,MaterialModel> map) {
		if (materialStockModel!=null && bomStockReports!=null) {
			for (BomStockReport bomStockReport : bomStockReports) {
				if (bomStockReport.getMaterialCode().equals(materialStockModel.getMaterialCode())) {
					MaterialModel materialModel = map.get(bomStockReport.getMaterialCode());
					if (materialModel!=null) {
						bomStockReport.setMaterialName(materialModel.getModel()+" "+materialModel.getSpecification());
						bomStockReport.setUnit(materialModel.getUnit());
					}
					
					if(bomStockReport.getYear()<materialStockModel.getYear()) {
						bomStockReport.setStock(materialStockModel.getStock());
					}else {
						if(bomStockReport.getMonth()<materialStockModel.getMonth()) {
							bomStockReport.setStock(materialStockModel.getStock());
						}else {
							if(bomStockReport.getDay()<materialStockModel.getDay()) {
								bomStockReport.setStock(materialStockModel.getStock());
							}
						}
					}
					
				}
			}
		}
		
	}

	private void fillBomStockReport(MaterialModel materialModel,List<BomStockReport> bomStockReports) {
		if (materialModel!=null) {
			
			BomStockReport bomStockReport = new BomStockReport();
			bomStockReport.setDeep(0);
			bomStockReport.setMaterialCode(materialModel.getCode());
			
			bomStockReports.add(bomStockReport);
			
			List<MaterialBomModel> materialBomModels = materialModel.getMaterialBoms();
			getMoreDeepBom(bomStockReports, materialBomModels,0);
		}
	}

	private void getMoreDeepBom(List<BomStockReport> bomStockReports,
			List<MaterialBomModel> materialBomModels,int deep) {
		if (materialBomModels!=null) {
			for (MaterialBomModel materialBomModel : materialBomModels) {
				BomStockReport subBomStockReport = new BomStockReport();
				subBomStockReport.setDeep(deep+1);
				subBomStockReport.setMaterialCode(materialBomModel.getMaterialCode());
				bomStockReports.add(subBomStockReport);
				getMoreDeepBom(bomStockReports, materialBomModel.getSubMaterialBoms(), deep+1);
			}
		}
	}

	
	@RequestMapping("download")
	public Model download(HttpServletRequest request,
			HttpServletResponse response, Model model) throws IOException {
		check(PermissionStatus.CREATE);

		String filename = RequestUtil.getValueByParam(request, "filename");
		String sheetname = RequestUtil.getValueByParam(request, "sheetname");
		if (filename != null) {
			String fullname = WebConstants.EXCEL_PATH + filename;
			response.addHeader("Content-Disposition", "attachment;filename="
					+ URLEncoder.encode(sheetname, "utf-8"));
			RequestDispatcher dispatcher = request
					.getRequestDispatcher(fullname);
			try {
				dispatcher.forward(request, response);
			} catch (ServletException e) {
				e.printStackTrace();
			} catch (IOException e) {
				response.flushBuffer();
			}
		}
		return model;
	}

	private List<MaterialBomModel> fillBoms(String materialCode) {
		if (!StringUtils.isBlank(materialCode)) {
			List<MaterialBomModel> materialBomModels = materialBomService
					.findByCode(materialCode);

			if (materialBomModels != null && materialBomModels.size() > 0) {
				for (MaterialBomModel materialBomModel : materialBomModels) {
					List<MaterialBomModel> subBomModels = fillBoms(materialBomModel
							.getMaterialCode());
					materialBomModel.setSubMaterialBoms(subBomModels);
				}
				return materialBomModels;
			} else {
				return null;
			}

		}
		return null;
	}

	private Page<MaterialStockModel> getDayStockPage(
			List<String> materialCodeList, Pageable pageable, Boolean ispage,
			int year, int month, int day) {
		if (materialCodeList != null) {
			Page<MaterialStockModel> materialStockModels = null;
			if (ispage) {
				materialStockModels = materialStockService
						.findByYearAndMonthAndDayMaterialCodeIn(year, month,
								day, materialCodeList, pageable);
			} else {
				materialStockModels = materialStockService
						.findByYearAndMonthAndDayMaterialCodeIn(year, month,
								day, materialCodeList, null);
			}
			return materialStockModels;
		}
		return null;
	}

	private Page<MaterialStockModel> getMonthStockPage(
			List<String> materialCodeList, Pageable pageable, Boolean ispage,
			int year, int month) {
		if (materialCodeList != null) {
			List<MaterialStockModel> materialStockModels = materialStockService
					.findByYearAndMonthAndMaterialCodeIn(year, month,
							materialCodeList);
			// key为materialCode-month
			Map<String, MaterialStockModel> resultMap = new HashMap<String, MaterialStockModel>();
			if (materialStockModels != null && materialStockModels.size() > 0) {
				for (MaterialStockModel materialStockModel : materialStockModels) {
					String materialCode = materialStockModel.getMaterialCode();
					String keyString = materialCode + "-"
							+ materialStockModel.getMonth();
					if (resultMap.containsKey(keyString)) {
						MaterialStockModel oldMaterialStockModel = resultMap
								.get(keyString);
						if (oldMaterialStockModel.getStock() < materialStockModel
								.getStock()) {
							resultMap.put(keyString, materialStockModel);
						}
					} else {
						resultMap.put(keyString, materialStockModel);
					}
				}
			}

			if (resultMap.size() > 0) {
				List<MaterialStockModel> result = new ArrayList<MaterialStockModel>();
				result.addAll(resultMap.values());
				Page<MaterialStockModel> stockPage = null;
				if (ispage) {
					stockPage = new PageImpl<MaterialStockModel>(result,
							pageable, result.size());
				} else {
					stockPage = new PageImpl<MaterialStockModel>(result);
				}

				return stockPage;
			}
		}
		return null;
	}

	private Page<MaterialStockModel> getYearStockPage(
			List<String> materialCodeList, Pageable pageable, boolean isPage,
			int year) {
		if (year > 0 && materialCodeList != null) {
			List<MaterialStockModel> materialStockModels = materialStockService
					.findByYearAndMaterialCodeIn(year, materialCodeList);
			// key为materialCode
			Map<String, MaterialStockModel> resultMap = new HashMap<String, MaterialStockModel>();
			if (materialStockModels != null && materialStockModels.size() > 0) {

				for (MaterialStockModel materialStockModel : materialStockModels) {
					String materialCode = materialStockModel.getMaterialCode();
					if (resultMap.containsKey(materialCode)) {
						MaterialStockModel oldMaterialStockModel = resultMap
								.get(materialCode);
						if (oldMaterialStockModel.getStock() < materialStockModel
								.getStock()) {
							resultMap.put(materialCode, materialStockModel);
						}
					} else {
						resultMap.put(materialCode, materialStockModel);
					}
				}
			}
			if (resultMap.size() > 0) {
				List<MaterialStockModel> result = new ArrayList<MaterialStockModel>();
				result.addAll(resultMap.values());
				Page<MaterialStockModel> stockPage = null;
				if (isPage) {
					stockPage = new PageImpl<MaterialStockModel>(result,
							pageable, result.size());
				} else {
					stockPage = new PageImpl<MaterialStockModel>(result);
				}

				return stockPage;

			}
		}
		return null;
	}

	/**
	 * 获取全部库存信息
	 * 
	 * @param pageRequest
	 * @param stockPage
	 * @param codeList
	 * @return
	 */
	private Page<MaterialStockModel> getDefaultStockPage(
			PageRequest pageRequest, Boolean isPage,
			Page<MaterialStockModel> stockPage, List<String> codeList) {
		List<CategoryModel> categoryModels = categoryService
				.findByCodeIn(codeList);
		if (categoryModels != null && categoryModels.size() > 0) {
			List<MaterialModel> materialModels = materialService
					.findByCategoryIn(categoryModels);
			if (materialModels != null) {
				Map<String, MaterialModel> materialMap = new HashMap<String, MaterialModel>();
				List<String> materialCodeList = new ArrayList<String>();
				parseMaterialInfo(materialModels, materialMap, materialCodeList);
				if (isPage) {
					stockPage = materialStockService.findByMaterialCodeIn(
							materialCodeList, pageRequest);
				} else {
					stockPage = materialStockService.findByMaterialCodeIn(
							materialCodeList, null);
				}
			}
		}
		return stockPage;
	}

	private void fillInfo(Page<MaterialStockModel> stockPage,
			Map<String, MaterialModel> map) {
		if (stockPage != null) {
			List<MaterialStockModel> materialStockModels = stockPage
					.getContent();
			if (materialStockModels != null && materialStockModels.size() > 0) {
				String materialCode = "";
				for (MaterialStockModel materialStockModel : materialStockModels) {
					materialCode = materialStockModel.getMaterialCode();
					if (map.containsKey(materialCode)) {
						MaterialModel materialModel = map.get(materialCode);
						if (materialModel != null) {
							String name = materialModel.getName()+" "+materialModel.getFullname();
							if (!StringUtils.isEmpty(materialModel.getColor())) {
								name += "("+materialModel.getColor()+")";
							}
							materialStockModel.setMaterialName(name);
							materialStockModel.setUnit(materialModel.getUnit());
						}
					}
				}
			}
		}
	}

	private void parseMaterialInfo(List<MaterialModel> materialModels,
			Map<String, MaterialModel> materialMap,
			List<String> materialCodeList) {
		if (materialModels != null && materialModels.size() > 0) {
			for (MaterialModel materialModel : materialModels) {
				materialMap.put(materialModel.getCode(), materialModel);
				materialCodeList.add(materialModel.getCode());
			}
		}

	}

	private void fillInfo(Page<MaterialStockModel> stockPage,
			String categoryCode) {
		if (stockPage != null) {
			List<MaterialStockModel> materialStockModels = stockPage
					.getContent();
			if (materialStockModels != null && materialStockModels.size() > 0) {
				CategoryModel categoryModel = categoryService
						.findByCode(categoryCode);

				Map<String, MaterialModel> map = materialService
						.getMapByCategory(categoryModel);
				for (MaterialStockModel materialStockModel : materialStockModels) {
					if (map.containsKey(materialStockModel.getMaterialCode())) {
						materialStockModel
								.setMaterialName(map.get(
										materialStockModel.getMaterialCode())
										.getName());
					}
				}
			}
		}
	}

	public MaterialService getMaterialService() {
		return materialService;
	}

	public void setMaterialService(MaterialService materialService) {
		this.materialService = materialService;
	}

	public CategoryService getCategoryService() {
		return categoryService;
	}

	public void setCategoryService(CategoryService categoryService) {
		this.categoryService = categoryService;
	}

	public MaterialBomService getMaterialBomService() {
		return materialBomService;
	}

	public void setMaterialBomService(MaterialBomService materialBomService) {
		this.materialBomService = materialBomService;
	}

}
